using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Testing;
using Volo.Abp.Uow;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Domain.Repositories;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Linq;
using Matrix.Configuration;
using Matrix.Configuration.DTOs;
using Matrix.Configuration.Contracts;

namespace Matrix.Configuration
{
    /// <summary>
    /// Matrix Configuration集成测试基类
    /// </summary>
    public abstract class MatrixConfigurationIntegrationTestBase : AbpIntegratedTest<MatrixConfigurationIntegrationTestModule>
    {
        protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
        {
            options.UseAutofac();
        }

  
        protected virtual async Task WithUnitOfWorkAsync(Func<Task> action)
        {
            using var scope = ServiceProvider.CreateScope();
            var unitOfWorkManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();

            using var uow = unitOfWorkManager.Begin(requiresNew: true);
            try
            {
                await action();
                await uow.CompleteAsync();
            }
            catch
            {
                await uow.RollbackAsync();
                throw;
            }
        }

        protected virtual async Task<T> WithUnitOfWorkAsync<T>(Func<Task<T>> action)
        {
            using var scope = ServiceProvider.CreateScope();
            var unitOfWorkManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();

            using var uow = unitOfWorkManager.Begin(requiresNew: true);
            try
            {
                var result = await action();
                await uow.CompleteAsync();
                return result;
            }
            catch
            {
                await uow.RollbackAsync();
                throw;
            }
        }

        protected virtual async Task WithUnitOfWorkAsync(Guid? tenantId, Func<Task> action)
        {
            using var scope = ServiceProvider.CreateScope();
            var unitOfWorkManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
            var currentTenant = scope.ServiceProvider.GetRequiredService<ICurrentTenant>();

            using (currentTenant.Change(tenantId))
            using (var uow = unitOfWorkManager.Begin(requiresNew: true))
            {
                try
                {
                    await action();
                    await uow.CompleteAsync();
                }
                catch
                {
                    await uow.RollbackAsync();
                    throw;
                }
            }
        }

        protected virtual async Task<T> WithUnitOfWorkAsync<T>(Guid? tenantId, Func<Task<T>> action)
        {
            using var scope = ServiceProvider.CreateScope();
            var unitOfWorkManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
            var currentTenant = scope.ServiceProvider.GetRequiredService<ICurrentTenant>();

            using (currentTenant.Change(tenantId))
            using (var uow = unitOfWorkManager.Begin(requiresNew: true))
            {
                try
                {
                    var result = await action();
                    await uow.CompleteAsync();
                    return result;
                }
                catch
                {
                    await uow.RollbackAsync();
                    throw;
                }
            }
        }

  
        protected virtual async Task<ConfigurationItem?> GetConfigurationItemAsync(Guid id)
        {
            return await WithUnitOfWorkAsync(async () =>
            {
                var dbContext = ServiceProvider.GetRequiredService<MatrixConfigurationDbContext>();
                return await dbContext.ConfigurationItems.FindAsync(id);
            });
        }

        protected virtual async Task<ConfigurationItem?> GetConfigurationItemAsync(
            string @namespace,
            string name,
            Guid? tenantId = null)
        {
            return await WithUnitOfWorkAsync(tenantId, async () =>
            {
                var dbContext = ServiceProvider.GetRequiredService<MatrixConfigurationDbContext>();
                return await dbContext.ConfigurationItems
                    .FirstOrDefaultAsync(x => x.Namespace == @namespace && x.Key == name);
            });
        }

        protected virtual async Task<bool> ConfigurationExistsAsync(string @namespace, string name, Guid? tenantId = null)
        {
            return await WithUnitOfWorkAsync(tenantId, async () =>
            {
                var dbContext = ServiceProvider.GetRequiredService<MatrixConfigurationDbContext>();
                return await dbContext.ConfigurationItems
                    .AnyAsync(x => x.Namespace == @namespace && x.Key == name);
            });
        }

        protected virtual async Task<int> GetConfigurationCountAsync(Guid? tenantId = null)
        {
            return await WithUnitOfWorkAsync(tenantId, async () =>
            {
                var dbContext = ServiceProvider.GetRequiredService<MatrixConfigurationDbContext>();
                return await dbContext.ConfigurationItems.CountAsync();
            });
        }

        /// <summary>
        /// 清理数据库中的所有配置项
        /// </summary>
        protected virtual async Task ClearDatabaseAsync()
        {
            await WithUnitOfWorkAsync(async () =>
            {
                var dbContext = ServiceProvider.GetRequiredService<MatrixConfigurationDbContext>();

                // 删除所有ConfigurationItems
                dbContext.ConfigurationItems.RemoveRange(dbContext.ConfigurationItems);
                await dbContext.SaveChangesAsync();
            });
        }

        /// <summary>
        /// 确保数据库是干净的，如果存在数据则清理
        /// </summary>
        protected virtual async Task EnsureCleanDatabaseAsync()
        {
            var count = await GetConfigurationCountAsync();
            if (count > 0)
            {
                await ClearDatabaseAsync();
            }
        }

        /// <summary>
        /// 创建配置项（用于测试）
        /// </summary>
        protected virtual async Task<ConfigurationItemDto> CreateConfigurationItemAsync(
            string @namespace,
            string key,
            string value,
            string category = "test",
            string description = "",
            string dataType = "string")
        {
            return await WithUnitOfWorkAsync(async () =>
            {
                var configurationAppService = ServiceProvider.GetRequiredService<IConfigurationAppService>();
                var createInput = new CreateConfigurationItemDto
                {
                    Namespace = @namespace,
                    Key = key,
                    Value = value,
                    DataType = dataType,
                    Category = category,
                    Description = description
                };

                return await configurationAppService.CreateAsync(createInput);
            });
        }
    }
}